package org.rcy.ruicingmarket.config;

import org.rcy.framework.security.authentication.provider.PasswordAuthenticationProvider;
import org.rcy.framework.security.exception.FormLoginEntryPoint;
import org.rcy.framework.security.filter.LoginAuthenticationFilter;
import org.rcy.framework.security.principal.UserProvider;
import org.rcy.ruicingmarket.login.OssLoginHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
import org.springframework.security.web.savedrequest.NullRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;

import java.util.ArrayList;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private BCryptPasswordEncoder encoder;
    @Autowired
    private UserProvider userProvider;
    @Autowired
    private CaptchaAuthentication captchaAuthentication;
    @Autowired
    private OssLoginHandler ossLoginHandler;

    /**
     *  authorizeRequests：所有security全注解配置实现的开端，表示开始说明需要的权限
     *  需要的权限分为两部分，第一部分是拦截的路径，第二部分是访问该路径需要的权限
     *  antMatchers  拦截的路径  permitAll()所有权限都可以，直接放行所有 hasAnyRole()这个方法可以指定角色	anyRequest任何请求
     *  authenticated需要认证后才能访问
     *  .and().csrf().disable(); 固定写法使csrf攻击失效，
     *  如果不设置为disabled，
     *  所有除了内部的请求，其余外部请求都被认为是在攻击我这个网站，全部拦截
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilter(new WebAsyncManagerIntegrationFilter())
                .headers()
                .cacheControl()
                .disable()
                .httpStrictTransportSecurity().and().and()
                .securityContext()
                .and().requestCache()
                .and().anonymous().and()
                .servletApi().and();
        http.headers().frameOptions().disable();

        http
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .mvcMatchers(  "/login/pin/**","/login/prepare","/login/codeverify",
                        "/menu/**","/role/**","/user/**","/delay/**","/index","/swagger-ui/**",
                        "/v3/api-docs/**")
                .permitAll()
                .anyRequest().authenticated()
                .and().csrf().disable();


        http.addFilterAt(loginAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        String loginPage = "http://localhost:3001/login";
        http.formLogin()
                .loginProcessingUrl("/login/verify")
                .loginPage(loginPage)
                .and().logout()
                .logoutUrl("/login/logout")
                .addLogoutHandler(ossLoginHandler)
                .logoutSuccessUrl(loginPage)
                .and().csrf().disable();

        http.setSharedObject(RequestCache.class, new NullRequestCache());
        http.exceptionHandling().authenticationEntryPoint(new FormLoginEntryPoint(loginPage,new ArrayList<>()));

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(formAuthenticationProvider());
    }

    @Bean
    public AuthenticationProvider formAuthenticationProvider() {
        return new PasswordAuthenticationProvider(userProvider);
    }

    @Bean
    public LoginAuthenticationFilter loginAuthenticationFilter() throws Exception {
        LoginAuthenticationFilter filter = new LoginAuthenticationFilter("/login/verify");
        filter.setPreFormLoginAuthentication(captchaAuthentication);
        filter.setAuthenticationSuccessHandler(ossLoginHandler);
        filter.setAuthenticationFailureHandler(ossLoginHandler);
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}